<?php

declare(strict_types=1);
/*
 * @Description: 日程service类
 * @Author: QianLong
 * @Date: 2019-10-13 12:39:05
 * @LastEditors    : QianLong
 * @LastEditTime   : 2024-04-11 11:09:30
 */

namespace App\Service;

use App\Exception\ApiException;
use Yurun\Util\HttpRequest;
use Hyperf\Di\Annotation\Inject;

class Schedule
{
    #[Inject]
    protected HttpRequest $http;

    /**
     * 计算新提醒/重复时间
     */
    public function getNextTimePeriod(int $start_date, int $end_date, string $date_type, int $loop_num, string $loop_type, bool $is_force = false): array
    {
        $current_time = time();
        $new_loop = $loop_num;
        if ($date_type == 'nl') {
            $nowYear = date('Y');
            $nowMonth = date('m');
            $nowDay = date('d');
            $year = date('Y', $start_date);
            $month = date('m', $start_date);
            $day = date('d', $start_date);
            $year_end = date('Y', $end_date);
            $month_end = date('m', $end_date);
            $day_end = date('d', $end_date);
            $calendar = new Calendar();
            $dsr_lunar = $calendar->lunar($year, $month, $day);
            $dsr_solar_timestamp = (int)strtotime($dsr_lunar['gregorian_year'] . '-' . $dsr_lunar['gregorian_month'] . '-' . $dsr_lunar['gregorian_day']);
            if ($current_time >= $dsr_solar_timestamp) {
                $dsr_result = $calendar->lunar($year, $month, $day); // 阴历日期
                $dsr_result_end = $calendar->lunar($year_end, $month_end, $day_end); // 阴历日期
                $now_result = $calendar->solar($nowYear, $nowMonth, $nowDay); //当前日期的阳历日期
                // 转换之后进行校验
                if ($dsr_result['lunar_year'] != $year) {
                    $dsr_result['lunar_year'] = $year;
                }
                if ($dsr_result['lunar_month'] != $month) {
                    $dsr_result['lunar_month'] = $month;
                }
                if ($dsr_result['lunar_day'] != $day) {
                    $dsr_result['lunar_day'] = $day;
                }
                if ($dsr_result_end['lunar_year'] != $year) {
                    $dsr_result_end['lunar_year'] = $year;
                }
                if ($dsr_result['lunar_month'] != $month) {
                    $dsr_result['lunar_month'] = $month;
                }
                if ($dsr_result['lunar_day'] != $day) {
                    $dsr_result['lunar_day'] = $day;
                }
                switch ($loop_type) {
                    case 'day':
                        $diff_day = $calendar->diffInDays($now_result, $dsr_result);
                        $addResult = $calendar->addDays($dsr_result, $diff_day);
                        $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        if ($nextTimeStamp < $current_time) {
                            $addResult = $calendar->addDays($dsr_result, $diff_day + $new_loop);
                            $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        }
                        break;
                    case 'week':
                        $diff_day = $calendar->diffInDays($now_result, $dsr_result);
                        $addResult = $calendar->addDays($dsr_result, $diff_day);
                        $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        if ($nextTimeStamp < $current_time) {
                            $addResult = $calendar->addDays($dsr_result, $diff_day + ($new_loop * 7));
                            $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        }
                        break;
                    case 'month':
                        $diff_month = $calendar->diffInMonths($now_result, $dsr_result);
                        $addResult = $calendar->addMonths($dsr_result, $diff_month);
                        $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        if ($nextTimeStamp < $current_time) {
                            $addResult = $calendar->addMonths($dsr_result, $diff_month + $new_loop);
                            $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        }
                        break;
                    case 'year':
                        $diff_years = $calendar->diffInYears($now_result, $dsr_result);
                        $addResult = $calendar->addYears($dsr_result, $diff_years);
                        $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        if ($nextTimeStamp < $current_time) {
                            $addResult = $calendar->addYears($dsr_result, $diff_years + $new_loop);
                            $nextTimeStamp = (int)strtotime($addResult['gregorian_year'] . '-' . $addResult['gregorian_month'] . '-' . $addResult['gregorian_day']);
                        }
                        break;
                    default:
                        throw new ApiException(-1, '农历制暂不支持所选级循环');
                        break;
                }
            } else {
                $nextTimeStamp = $dsr_solar_timestamp;
            }
            return [$nextTimeStamp, $nextTimeStamp];
        }else{
            if (($start_date < $current_time && $end_date < $current_time) || $is_force) {
                $date1 = new \DateTime(date('Y-m-d', $start_date));
                $date2 = new \DateTime(date('Y-m-d'));
                $interval = $date1->diff($date2);
                $cha = 0;
                $yushu = 0;

                switch ($loop_type) {
                    case 'hour':
                        $cha = ceil(($current_time - $start_date) / ($loop_num * 3600));
                        $yushu = intval(($current_time - $start_date) % ($loop_num * 3600));
                        break;
                    case 'day':
                        $days = $interval->format('%a');
                        $cha = ceil($days / $loop_num);
                        $yushu = intval($days % $loop_num);
                        break;
                    case 'week':
                        $days = $interval->format('%a');
                        $cha = ceil($days / ($loop_num * 7));
                        $yushu = intval($days % ($loop_num * 7));
                        break;
                    case 'month':
                        $months = $interval->format('%y') * 12 + $interval->format('%m');
                        $cha = ceil($months / $loop_num);
                        $yushu = intval($months % $loop_num);
                        break;
                    case 'year':
                        $years = $interval->format('%y');
                        $cha = ceil($years / $loop_num);
                        $yushu = intval($years % $loop_num);
                        break;
                } 

                $new_loop = $yushu === 0 ? ($cha * $loop_num + $loop_num) : ($cha * $loop_num);

                $date_interval_spec = $this->getIntervalSpec($loop_type, (int)$new_loop);
                $start_date_time = new \DateTime(date('Y-m-d', $start_date));
                $end_date_time = new \DateTime(date('Y-m-d', $end_date));
                $start_date_time->add(new \DateInterval($date_interval_spec));
                $end_date_time->add(new \DateInterval($date_interval_spec));
                return [$start_date_time->getTimestamp(), $end_date_time->getTimestamp()];
            } else {
                return [$start_date, $end_date];
            }
        }
    }

    public function getIntervalSpec(string $loop_type, int $loop_num): string
    {
        switch ($loop_type) {
            case 'hour':
                return 'PT' . $loop_num . 'H';
            case 'day':
                return 'P' . $loop_num . 'D';
            case 'week':
                return 'P' . ($loop_num * 7) . 'D';
            case 'month':
                return 'P' . $loop_num . 'M';
            case 'year':
                return 'P' . $loop_num . 'Y';
        }
    }
}
